import asyncio
import functools
from datetime import datetime

from pywebio import output, pin
import pywebio
from pywebio.output import PopupSize

from emi.bar.data import Interval, RankMeta
from emi.bar.db import RankDB
from emi.model import Market
from emi.util import utils
from emiui.chart import echarts


class RankDBUI:

    def __init__(self,market:Market):
        self.market = market
        self.rank_db = None
        try:
            rank_metas = self.market.getRankMetas()
        except NotImplementedError:
            rank_metas = []
        self.rank_metas = rank_metas


    async def show(self):

        if not self.rank_metas:
            output.put_text("没有数据")
            return

        rank_metas_index_option = [{
                "label":"---",
                'value':-1,
                "selected":False,
            }]

        for i in range(0,len(self.rank_metas)):
            rank_meta = self.rank_metas[i]
            rank_metas_index_option.append({
                "label":f"{rank_meta.label}({rank_meta.name})",
                'value':i,
                "selected":False,
            })

        pin.put_select("rank_option", options=rank_metas_index_option,  label="排名项目(RankMeta):")
        async def _on_rank_changed(index):
            if index < 0:
                return
            rank_meta = self.rank_metas[index]
            rank_db = self.market.getRankDB(rank_meta)
            await self._on_selected_rank_db(rank_db,rank_meta)

        pin.pin_on_change("rank_option",onchange=_on_rank_changed)

        pin.put_select("day_option", [])
        async def _on_day_option(index):
            await self.refresh()
        pin.pin_on_change("day_option", onchange=_on_day_option)

        output.put_markdown("------")
        output.put_row([
            pin.put_input("q_category",label='category'),
            pin.put_input("q_max_order",label='max_order',type=pywebio.input.NUMBER,value=3),
            pin.put_input("q_min_value",label='min_value',type=pywebio.input.NUMBER,value=50),
            pin.put_input("q_min_count",label='min_count',type=pywebio.input.NUMBER),
            output.put_scope("search_btn_scope").style("width: 100px"),

        ])


        output.put_markdown("------")
        output.put_scope("_rank_db_main")



    async def _on_selected_rank_db(self,rank_db:RankDB,rank_meta:RankMeta):
        self.rank_db = rank_db
        self.rank_meta = rank_meta
        with output.use_scope("search_btn_scope",clear=True):
            pass
        loop = asyncio.get_event_loop()
        days = await loop.run_in_executor(None, rank_db.get_day_list)
        if not days:
            output.put_text("无数据")
            return
        days.sort(reverse=True)
        day_option_data = []
        for index,day in enumerate(days):
            day_option_data.append({
                "label": day.strftime("%Y-%m-%d"),
                "value": day.strftime("%Y-%m-%d"),
                "selected": index == 0,
            })
        pin.pin_update("day_option",options=day_option_data)

        if day_option_data:
            with output.use_scope("search_btn_scope",clear=True):
                output.put_button("搜索",onclick=self.refresh)


        # if day_option_data:
        #     await self.refresh()


    async def refresh(self):
        with output.use_scope("_rank_db_main",clear=True):
            selected_day_value = await pin.pin['day_option']
            min_value = await pin.pin['q_min_value']
            max_order = await pin.pin['q_max_order']
            min_count = await pin.pin['q_min_count']
            q_category = await pin.pin['q_category']

            if not selected_day_value:
                output.put_text("无数据")
                return
            selected_day = datetime.strptime(selected_day_value,"%Y-%m-%d")

            data_list = []
            data_list.append([
                "code",
                "name",
                "time",
                "category",
                "value",
                "order",
                "avg value",
                "count"
            ])
            rank_bars = self.rank_db.get_best(selected_day,detail=False, interval=Interval.DAILY,
                                              min_value=min_value,
                                              max_order=max_order,
                                              min_count = min_count)
            if q_category:
                ## 查找指定行业分类下的数据。
                new_list = []
                for rank in rank_bars:
                    if rank.category_code and rank.category_code.__contains__(q_category):
                        new_list.append(rank)
                rank_bars = new_list

            total_size = len(rank_bars)
            if total_size > 100:
                rank_bars = rank_bars[:100]
                output.put_text(f"总共有{total_size}个结果, 只展示前100个!")
            else:
                output.put_text(f"总共有{total_size}个结果")

            for rank_bar in rank_bars:
                data_list.append([
                    output.put_button(rank_bar.symbol,
                                      small=True,
                                      color='light',
                                      onclick=functools.partial(self._popup_chart, rank_bar.symbol,rank_bar.name,self.rank_meta.category_type)),
                    #rank_bar.symbol,
                    rank_bar.name,
                    rank_bar.datetime.strftime("%Y-%m-%d"),
                    rank_bar.category_code,
                    f"{rank_bar.value:.2f}",
                    rank_bar.order,
                    f"{rank_bar.value_avg:.2f}",
                    rank_bar.count,
                ])
            output.put_table(data_list)

    def _popup_chart(self, code:str,name:str,category_type:int = None):
        market = self.market
        title = f"{name}({code})行情图"
        output.popup(title=title, content=[
            output.put_loading(),
            output.put_text("正在加载中....")
        ])

        try:
            day_db = market.get_today_db(category_type)
            d_bars = day_db.get_bars(symbol=code)
        except NotImplementedError:
            d_bars = None
            day_db = None

        try:
            bar_db = market.get_bar_db(category_type)
            k_bars = bar_db.get_bars(symbol=code, with_detail=False)
            for bar in k_bars:
                ### 根据复权因子，转换到实时价格。
                bar.high = bar.high / bar.price_adjust
                bar.low = bar.low / bar.price_adjust
                bar.open = bar.open / bar.price_adjust
                bar.close = bar.close / bar.price_adjust
                bar.pre_close = bar.pre_close / bar.price_adjust
            if day_db and k_bars:
                latest_bar = k_bars[-1]
                today_bar = day_db.get_tick(code)
                if today_bar \
                        and not utils.is_same_day(latest_bar.datetime,today_bar.datetime) \
                        and today_bar.datetime > latest_bar.datetime:
                    if category_type is not None:
                        ### 行业分类数据重新复权值。
                        base_price = latest_bar.close
                        today_bar.open = base_price * ( 1+ (today_bar.open - today_bar.pre_close ) / today_bar.pre_close)
                        today_bar.high = base_price * ( 1+ (today_bar.high - today_bar.pre_close ) / today_bar.pre_close)
                        today_bar.low = base_price * ( 1+ (today_bar.low - today_bar.pre_close ) / today_bar.pre_close)
                        today_bar.close = base_price * ( 1+ (today_bar.close - today_bar.pre_close ) / today_bar.pre_close)
                        today_bar.pre_close = base_price

                    k_bars.append(today_bar) ## 加入当天实时数据

        except NotImplementedError:
            k_bars = None

        width = "800px"
        height = "400px"
        tab_list = []
        if d_bars:
            chart = echarts.build_kbar_chart(d_bars)
            chart.width = width
            chart.height = height
            tab_list.append({
                "title": '实时',
                "content": [output.put_html(chart.render_notebook())]
            })
        if k_bars:
            k_chart = echarts.build_kbar_chart(k_bars)
            k_chart.width = width
            k_chart.height = height
            tab_list.append({
                "title": 'K线',
                "content": [output.put_html(k_chart.render_notebook())]
            })

        output.popup(title=title, content=[
            output.put_tabs(tab_list) if tab_list else output.put_text("没有行情数据！")
        ], size=PopupSize.LARGE)

if __name__ == '__main__':
    from emi.core.App import App

    context = App()
    # db_source = DBSource.of_name(context, "china_market")  ## 中国市场结构数据
    #
    # market_meta = MarketMetaStorage(db_source)
    # ui = MarketMetaUI(market_meta)
    # pywebio.start_server(functools.partial(MarketMetaUI.show, ui),
    #                      port=8080,
    #                      debug=True)